package com.CST.util;


import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.*;

/**
 * @author qtx
 * @since 2023/5/11
 */
public class ComputeUtil {


    public void test() {
        String s = "$*($+$*$)/$+($/$+$)";
        Queue<String> strings = new LinkedList<>();
        DecimalFormat format = new DecimalFormat("0.00");
        ArrayList<String> list = new ArrayList<>();
        for (int i = 0; i < 8; i++) {
            String num = format.format(Math.random() * 100);
            list.add(num);
            strings.add(num);
        }
        System.out.println("bigDecimal:" + list);
        List<String> param = param(s, strings);
        System.out.println("compute:" + compute(param));
    }

    public List<String> param(String s, Queue<String> queue) {
        ArrayList<String> list = new ArrayList<>();
        for (char c : s.toCharArray()) {
            if (c == '$') {
                list.add(queue.poll());
            } else {
                list.add(String.valueOf(c));
            }
        }
        return list;
    }

    public BigDecimal compute(List<String> s) {
        // Write your code here
        if (s == null || s.size() == 0) return new BigDecimal(0);
        Stack<BigDecimal> nums = new Stack<>();   //数字栈
        Stack<String> ops = new Stack<>();   //操作符栈
        BigDecimal num;
        for (int i = 0; i < s.size(); i++) {
            String c = s.get(i);
            if (Objects.equals(c, " ")) {
                continue;
            }
            if (isNumeric(c)) {            //字符串转化数字
                num = new BigDecimal(c);
                while (i < s.size() - 1 && isNumeric(s.get(i + 1))) {
                    num = num.multiply(new BigDecimal(10))
                            .add(new BigDecimal(s.get(i + 1)));
                    i++;
                }
                nums.push(num);            //数字直接存入栈中
            } else if (Objects.equals(c, "(")) {        //左括号直接存入
                ops.push(c);
            } else if (Objects.equals(c, ")")) {        //遇到右括号
                while (!Objects.equals(ops.peek(), "(")) {        //对栈顶两数字进行运算
                    nums.push(operation(ops.pop(), nums.pop(), nums.pop()));
                }
                ops.pop();
            } else if (Objects.equals(c, "+") || Objects.equals(c, "-") || Objects.equals(c, "*") || Objects.equals(c,
                    "/")) {   //遇到操作符
                while (!ops.isEmpty() && precedence(c, ops.peek())) {        //对栈顶两数字进行运算
                    nums.push(operation(ops.pop(), nums.pop(), nums.pop()));
                }
                ops.push(c);
            }
        }
        while (!ops.isEmpty()) {    //取出栈顶的数字进行操作
            nums.push(operation(ops.pop(), nums.pop(), nums.pop()));
        }
        return nums.pop();
    }

    private static BigDecimal operation(String op, BigDecimal b, BigDecimal a) {
        switch (op) {
            case "+":
                return a.add(b);   //加法
            case "-":
                return a.subtract(b);  //减法
            case "*":
                return a.multiply(b);   //乘法
            case "/":
                return a.divide(b, 4, RoundingMode.HALF_DOWN);   //除法
        }
        return new BigDecimal(0);
    }

    private static boolean precedence(String op1, String op2) {
        if (Objects.equals(op2, "(") || Objects.equals(op2, ")")) {
            return false;
        }
        return (!Objects.equals(op1, "*") && !Objects.equals(op1, "/")) || (!Objects.equals(op2,
                "+") && !Objects.equals(
                op2, "-"));
    }

    public static boolean isNumeric(final CharSequence cs) {
        if (cs == null || cs.length() == 0) {
            return false;
        }
        final int sz = cs.length();
        for (int i = 0; i < sz; i++) {
            if (cs.charAt(i) == '.') {
                continue;
            }
            if (!Character.isDigit(cs.charAt(i))) {
                return false;
            }
        }
        return true;
    }
}
